# Copyright (c) 2019 Presto Labs Pte. Ltd.
# Author: xguo

import json
import logging

from absl import app, flags

from coin.experimental.xguo.fruit.util.fee import get_fee_rate
from coin.experimental.xguo.fruit.grape.simple_pricer import SimplePricer, OrderSide
from coin.experimental.xguo.fruit.base.event_clock import (
    event_clock_scheduler,
    event_clock,
)
from coin.experimental.xguo.fruit.base.strategy_sim_base import (
    BaseSimStrategy,
    BaseStrategyConfig,
)
from coin.strategy.mm.simple_sim.executors import PassiveSimExecutor

FLAGS = flags.FLAGS


def get_lot_size(product):
  if product.base.currency == 'EOS':
    lot_size = 20
  elif product.base.currency == 'BTC':
    lot_size = 0.1
  elif product.base.currency == 'ETH':
    lot_size = 1
  elif product.base.currency == 'XRP':
    lot_size = 100
  elif product.base.currency == 'LTC':
    lot_size = 1
  elif product.base.currency == 'BCHABC':
    lot_size = 1
  else:
    raise ValueError()
  return lot_size


class DummSimStrategy(BaseSimStrategy):
  def __init__(self, config):
    super().__init__(config)
    self._pricer = SimplePricer(self.product_list)

    self._executor = {}
    for product in self.product_list:
      fee_bp = get_fee_rate(product)
      maker_fee = fee_bp[0] * 1e-4
      taker_fee = fee_bp[1] * 1e-4
      self.edge_bp = fee_bp[0] * 2 + 3
      lot_size = get_lot_size(product)
      executor = PassiveSimExecutor(
          lot_size=lot_size,
          min_pos=0,
          max_pos=lot_size * 4,
          maker_fee=maker_fee,
          taker_fee=taker_fee,
          execution_delay=0,
          post_only=False,
          min_fire_period=4 * 1e9,
      )
      self._executor[product] = executor
    event_clock_scheduler.add_periodic_task(1800, self.log_sim_time)
    event_clock_scheduler.add_periodic_task(300, self.pnl_snapshot)
    event_clock_scheduler.add_periodic_task(3600 * 12, self.save_sim_result)
    self.pnl_report = []

  @property
  def executors(self):
    return self._executor

  def on_book(self, book):
    timestamp = book.timestamp
    self._pricer.update(book)
    if not self._pricer.is_ready():
      return

    self._executor[book.product].update_book(book)
    orders = self._pricer.gen_mm_orders(edge_bp=self.edge_bp)

    for product, order in orders.items():
      if product == book.product:
        continue

      self._executor[product].post(
          timestamp=timestamp,
          buy_price=order[OrderSide.BUY],
          sell_price=order[OrderSide.SELL],
      )
    self._logger.debug('Submit order: %s', event_clock.now())

  def on_trade(self, product, trade_event):
    self._executor[product].update_trade(trade_event)

  def pnl_snapshot(self):
    timestamp = event_clock.timestamp
    result = {
        'timestamp': timestamp,
        'human_readable_timestamp': str(event_clock.now()),
        'data': {},
    }
    for product, executor in self.executors.items():
      result['data'][product.symbol] = executor.get_summary()
    print(json.dumps(result, indent=2))
    self.pnl_report.append(result)

  def save_sim_result(self):
    filename = self.strategy_config.sim_config.get('result_file')
    if not filename:
      filename = str(event_clock.timestamp) + '.json'
    with open(filename, 'w') as out_file:
      json.dump(self.pnl_report, out_file)


def main(_):
  config = BaseStrategyConfig.from_file(FLAGS.config)
  strategy = DummSimStrategy(config)
  strategy.run()
  strategy.save_sim_result()


if __name__ == '__main__':
  flags.DEFINE_string('config', None, 'Strategy config file.')

  logging.basicConfig(level='INFO', format='%(levelname)s %(asctime)s %(name)s] %(message)s')
  app.run(main)
